package com.gopay.solution.manager.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import com.gopay.common.cache.client.RedisClient;
import com.gopay.common.cache.constants.CacheCleanType;
import com.gopay.common.cache.constants.RedisConstants;
import com.gopay.common.cache.service.CacheCleanService;
import com.gopay.common.cache.vo.CacheClean;
import com.gopay.common.constants.Constants;
import com.gopay.common.util.FastJsonUtil;
import com.gopay.solution.domain.po.SsTransFeeDtl;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.crypto.RuntimeCryptoException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.gopay.common.constants.solution.SolutionTypeConstant;
import com.gopay.solution.dao.SolutionRuleDtlDAO;
import com.gopay.solution.dao.SsAcctSolutionRelDAO;
import com.gopay.solution.domain.po.SolutionRuleDtl;
import com.gopay.solution.domain.po.SsAcctSolutionRel;
import com.gopay.solution.domain.vo.Solution;
import com.gopay.solution.manager.SolutionManager;
import com.gopay.solution.manager.SsAcctSolutionManager;

/**
 * 账户与方案
 * @SsApSolutionRelManager.java
 * @author liujy
 * @2013-4-7 下午2:08:39  www.gopay.com.cn Inc.All rights reserved.
 */
@Service("ssAcctSolutionManager")
public class SsAcctSolutionManagerImpl implements SsAcctSolutionManager{

    private  final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    RedisConstants redisConstants;

    @Resource(name="cacheCleanService")
    private CacheCleanService cacheCleanService;
    
    /**
     * 账户产品与方案关系
     */
    @Resource(name = "ssAcctSolutionRelDAO")
    private SsAcctSolutionRelDAO ssAcctSolutionRelDAO;
    
    @Resource(name = "ssTransDtlDAO")
    private SolutionRuleDtlDAO<SolutionRuleDtl, Serializable> ssTransDtlDAO;
    
    @Resource(name = "ssTransFeeDtlDAO")
    private SolutionRuleDtlDAO<SolutionRuleDtl, Serializable> ssTransFeeDtlDAO;
    
    @Resource(name = "ssTransPayChanDtlDAO")
    private SolutionRuleDtlDAO<SolutionRuleDtl, Serializable> ssTransPayChanDtlDAO;
    
    @Resource(name = "ssTransSettleDtlDAO")
    private SolutionRuleDtlDAO<SolutionRuleDtl, Serializable> ssTransSettleDtlDAO;

    @Resource(name = "ssAcctGainDtlDAO")
    private SolutionRuleDtlDAO<SolutionRuleDtl, Serializable> ssAcctGainDtlDAO;
    
    @Resource(name = "ssTransSoluManager")
    private SolutionManager ssTransSoluManager;
    @Resource(name = "ssTransFeeSoluManager")
    private SolutionManager ssTransFeeSoluManager;
    @Resource(name = "ssTransPayChanSoluManager")
    private SolutionManager ssTransPayChanSoluManager;
    @Resource(name = "ssAcctGainSoluManager")
    private SolutionManager ssAcctGainSoluManager;
    @Resource(name = "ssUIConfigSoluManager")
    private SolutionManager ssUIConfigSoluManager;
    
    @Resource(name="ssGpProdComConfSoluManager")
    private SolutionManager ssGpProdComConfSoluManager;
    
    @Resource(name="ssGpProdRiskFundConfSoluManager")
    private SolutionManager ssGpProdRiskFundConfSoluManager;

    @Resource(name = "ssTransProfitSoluManager")
    private SolutionManager ssTransProfitSoluManager;
    
    @Resource(name = "ssTransSettleSoluManager")
    private SolutionManager ssTransSettleSoluManager;

    @Override
    public SsAcctSolutionRel findRelByAcctId(String acctId, String solutionType) {
        String hql = "from SsAcctSolutionRel where acctId=:acctId and solutionType=:solutionType";
        Map<String, Object> param = new HashMap<String, Object>();
        param.put("acctId", acctId);
        param.put("solutionType", solutionType);
        // 产寻账户与方案关系表(solutionType=TRN)
        List<SsAcctSolutionRel> ssAcctSolutionRels = ssAcctSolutionRelDAO.findByHql(hql, param);
        if(ssAcctSolutionRels == null || ssAcctSolutionRels.isEmpty()){
            return null;
        }
        return ssAcctSolutionRels.get(0);
    }
    
    @Override
    public List<SolutionRuleDtl> findDtlsByAcctIdAndIntTxnCd(String solutionId, String solutionType){
        
        StringBuilder hql = new StringBuilder(" from ");
        if(SolutionTypeConstant.TRANS_TRN.equals(solutionType)){
            hql.append(" SsTransDtl ");
        }else if(SolutionTypeConstant.ACCT_GAIN.equals(solutionType)){
            hql.append(" SsAcctGainDtl ");
        }
        hql.append(" where solutionId=:solutionId");
        
        Map<String, Object> param = new HashMap<String, Object>();
        param.put("solutionId", Long.valueOf(solutionId));

        if(SolutionTypeConstant.TRANS_TRN.equals(solutionType)){
            return ssTransDtlDAO.findByHql(hql.toString(), param);
        }else if(SolutionTypeConstant.ACCT_GAIN.equals(solutionType)){
            return ssAcctGainDtlDAO.findByHql(hql.toString(), param);
        }
        return null;
    }
    
    @Override
    public List<SolutionRuleDtl> findDtlsByAcctIdAndIntTxnCd(String solutionId, String intTxnCd, String solutionType){
        
        StringBuilder hql = new StringBuilder(" from ");
        if(SolutionTypeConstant.TRANS_FEE.equals(solutionType)){
            hql.append(" SsTransFeeDtl ");
        }else if(SolutionTypeConstant.TRANS_PAYCHAN.equals(solutionType)){
            hql.append(" SsTransPayChanDtl ");
        }else if(SolutionTypeConstant.TRANS_SETTLE.equals(solutionType)){
            hql.append(" SsTransSettleDtl ");
        }
        hql.append(" where solutionId=:solutionId and gopayIntTxnCd=:gopayIntTxnCd ");
        
        Map<String, Object> param = new HashMap<String, Object>();
        param.put("solutionId", Long.valueOf(solutionId));
        param.put("gopayIntTxnCd", intTxnCd);
        
        if(SolutionTypeConstant.TRANS_FEE.equals(solutionType)){
            return ssTransFeeDtlDAO.findByHql(hql.toString(), param);
        }else if(SolutionTypeConstant.TRANS_PAYCHAN.equals(solutionType)){
            return ssTransPayChanDtlDAO.findByHql(hql.toString(), param);
        }else if(SolutionTypeConstant.TRANS_SETTLE.equals(solutionType)){
            return ssTransSettleDtlDAO.findByHql(hql.toString(), param);
        }
        return null;
    }
    
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public void deleteRelAndChild(SsAcctSolutionRel rel, String solutionType){
        // 删除关系表、方案表及所有明细表相关记录
        if (rel != null) {
            if(SolutionTypeConstant.ACCT_GAIN.equals(solutionType)){
                ssAcctGainSoluManager.delete(rel.getSolutionId());
            }else if(SolutionTypeConstant.TRANS_TRN.equals(solutionType)){
                ssTransSoluManager.delete(rel.getSolutionId());
            }else if(SolutionTypeConstant.TRANS_UIS.equals(solutionType)){
                ssUIConfigSoluManager.delete(rel.getSolutionId());
                cacheCleanService.cleanCache(new CacheClean(CacheCleanType.BETWEEN, redisConstants.getRedisEnvironment()+":"+Constants.CACHE_CHANNEL_SOLUTION, solutionType));
            }else{
                throw new RuntimeCryptoException("deleteRelAndChild()不支持此solutionType：" + solutionType);
            }
            ssAcctSolutionRelDAO.delete(rel);
        }
    }
    
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public void deleteRelAndChild(SsAcctSolutionRel rel, String intTxnCd, String solutionType,String prodCode,String acctId){
        // 删除关系表、方案表及所有明细表相关记录
        if (rel != null) {
            Solution s = null;
            if(SolutionTypeConstant.TRANS_FEE.equals(solutionType)){
                s = ssTransFeeSoluManager.loadBySeqAndIntTxnCd(rel.getSolutionId(), intTxnCd);
            }else if(SolutionTypeConstant.TRANS_PAYCHAN.equals(solutionType)){
                s = ssTransPayChanSoluManager.loadBySeqAndIntTxnCd(rel.getSolutionId(), intTxnCd);
            }else if(SolutionTypeConstant.TRANS_PROFIT.equals(solutionType)){
                s = ssTransProfitSoluManager.loadBySeqAndIntTxnCd(rel.getSolutionId(), intTxnCd);
            }else if(SolutionTypeConstant.TRANS_SETTLE.equals(solutionType)){
                s = ssTransSettleSoluManager.loadBySeqAndIntTxnCd(rel.getSolutionId(), intTxnCd);
            }else{
                throw new RuntimeCryptoException("deleteRelAndChild()不支持此solutionType：" + solutionType);
            }
            s.setRuleDtls(new ArrayList<SolutionRuleDtl>());
            if(SolutionTypeConstant.TRANS_FEE.equals(solutionType)){
                //清除缓存 add by wangdong 20160906
                cleanFeeCacheByAcctId(s,intTxnCd,solutionType,prodCode,acctId);
            }else if(SolutionTypeConstant.TRANS_PAYCHAN.equals(solutionType)){
                ssTransPayChanSoluManager.modifyBySeqAndIntTxnCd(s, intTxnCd);
                cacheCleanService.cleanCache(new CacheClean(FastJsonUtil.getKey(redisConstants.getRedisEnvironment(), Constants.CACHE_CHANNEL_SOLUTION, null, intTxnCd, solutionType), acctId));
            }else if(SolutionTypeConstant.TRANS_PROFIT.equals(solutionType)){
            	ssTransProfitSoluManager.modifyBySeqAndIntTxnCd(s, intTxnCd);
            }else if(SolutionTypeConstant.TRANS_SETTLE.equals(solutionType)){
            	ssTransSettleSoluManager.modifyBySeqAndIntTxnCd(s, intTxnCd);
            }
            
        }
    }
    
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public SsAcctSolutionRel saveRelAndChild(SsAcctSolutionRel rel, Solution s) {
       
        s = saveApSolitionAndChild(s, rel.getSolutionType());
        
        rel.setSolutionId(s.getMeta().getSolutionId());
        ssAcctSolutionRelDAO.save(rel);
        
        return rel;
    }
    
    /**
     * 保存关系、方案、明细
     * @param acctProdCode
     * @param gopayIntTxnCd
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public Solution saveApSolitionAndChild(Solution s, String solutionType) {
        if(SolutionTypeConstant.TRANS_FEE.equals(solutionType)){
            ssTransFeeSoluManager.save(s);
        }else if(SolutionTypeConstant.TRANS_PAYCHAN.equals(solutionType)){
            ssTransPayChanSoluManager.save(s);
        }else if(SolutionTypeConstant.TRANS_TRN.equals(solutionType)){
            ssTransSoluManager.save(s);
        }else if(SolutionTypeConstant.ACCT_GAIN.equals(solutionType)){
            ssAcctGainSoluManager.save(s);
        }else if(SolutionTypeConstant.TRANS_UIS.equals(solutionType)){
            ssUIConfigSoluManager.save(s);
        }else if(SolutionTypeConstant.GP_COM.equals(solutionType)){
            ssGpProdComConfSoluManager.save(s);
        }else if(SolutionTypeConstant.GP_RISKFUND.equals(solutionType)){
            ssGpProdRiskFundConfSoluManager.save(s);
        }else if(SolutionTypeConstant.TRANS_PROFIT.equals(solutionType)){
            ssTransProfitSoluManager.save(s);
        }else if(SolutionTypeConstant.TRANS_SETTLE.equals(solutionType)){
            ssTransSettleSoluManager.save(s);
        }else{
            throw new RuntimeCryptoException("saveApSolitionAndChild()不支持此solutionType：" + solutionType);
        }
        return s;
    }
    
    /**
     * 更新方案、明细（非关联交易码）
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public void updateSolutionChild(Solution s, String solutionType) {
        if(SolutionTypeConstant.TRANS_TRN.equals(solutionType)){
            ssTransSoluManager.modify(s);
        }else if(SolutionTypeConstant.ACCT_GAIN.equals(solutionType)){
            ssAcctGainSoluManager.modify(s);
        }else if(SolutionTypeConstant.TRANS_UIS.equals(solutionType)){
            ssUIConfigSoluManager.modify(s);
            cacheCleanService.cleanCache(new CacheClean(CacheCleanType.BETWEEN, redisConstants.getRedisEnvironment()+":"+Constants.CACHE_CHANNEL_SOLUTION, solutionType));
        }else if(SolutionTypeConstant.GP_COM.equals(solutionType)){
            ssGpProdComConfSoluManager.modify(s);
        }else if(SolutionTypeConstant.GP_RISKFUND.equals(solutionType)){
            ssGpProdRiskFundConfSoluManager.modify(s);
        }else{
            throw new RuntimeCryptoException("不支持此solutionType：" + solutionType);
        }
    }
    
    /**
     * 更新方案、明细（关联交易码）
     */
//    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public void updateSolutionChild(Solution s, String intTxnCd, String solutionType, String prodCode, String acctId,String payChannel) {
        if(SolutionTypeConstant.TRANS_FEE.equals(solutionType)){
            //update by wangdong 20160905 增加缓存清理功能，精准清理
            cleanFeeCacheByField(s, intTxnCd, solutionType, prodCode, acctId,payChannel);
        }else if(SolutionTypeConstant.TRANS_PAYCHAN.equals(solutionType)){
            ssTransPayChanSoluManager.modifyBySeqAndIntTxnCd(s, intTxnCd);
            cacheCleanService.cleanCache(new CacheClean(FastJsonUtil.getKey(redisConstants.getRedisEnvironment(), Constants.CACHE_CHANNEL_SOLUTION, null, intTxnCd, solutionType), acctId));
        }else if(SolutionTypeConstant.TRANS_PROFIT.equals(solutionType)){
            ssTransProfitSoluManager.modifyBySeqAndIntTxnCd(s, intTxnCd);
        }else if(SolutionTypeConstant.TRANS_SETTLE.equals(solutionType)){
            ssTransSettleSoluManager.modifyBySeqAndIntTxnCd(s, intTxnCd);
        }else{
            throw new RuntimeCryptoException("不支持此solutionType：" + solutionType);
        }
    }

    /**
     * 更新方案、明细（非关联交易码）
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public Solution load(long solutionId, String solutionType) {
        Solution s = null;
        if(SolutionTypeConstant.TRANS_TRN.equals(solutionType)){
            s = ssTransSoluManager.load(solutionId);
        }else if(SolutionTypeConstant.ACCT_GAIN.equals(solutionType)){
            s = ssAcctGainSoluManager.load(solutionId);
        }else if(SolutionTypeConstant.TRANS_UIS.equals(solutionType)){
            s = ssUIConfigSoluManager.load(solutionId);
        }else if(SolutionTypeConstant.GP_COM.equals(solutionType)){
            s = ssGpProdComConfSoluManager.load(solutionId);
        }else if(SolutionTypeConstant.GP_RISKFUND.equals(solutionType)){
            s = ssGpProdRiskFundConfSoluManager.load(solutionId);
        }
        return s;
    }
    
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = { Exception.class, RuntimeException.class })
    public Solution load(long solutionId, String intTxnCd, String solutionType) {
        Solution s = null;
        if(SolutionTypeConstant.TRANS_FEE.equals(solutionType)){
            s = ssTransFeeSoluManager.loadBySeqAndIntTxnCd(solutionId, intTxnCd);
        }else if(SolutionTypeConstant.TRANS_PAYCHAN.equals(solutionType)){
            s = ssTransPayChanSoluManager.loadBySeqAndIntTxnCd(solutionId, intTxnCd);
        }else if(SolutionTypeConstant.TRANS_PROFIT.equals(solutionType)){
            s = ssTransProfitSoluManager.loadBySeqAndIntTxnCd(solutionId, intTxnCd);
        }else if(SolutionTypeConstant.TRANS_SETTLE.equals(solutionType)){
            s = ssTransSettleSoluManager.loadBySeqAndIntTxnCd(solutionId, intTxnCd);
        }else if(SolutionTypeConstant.TRANS_UIS.equals(solutionType)){//生产bug6期 新增 lx 2017-7-5 11:08:05
            s = ssUIConfigSoluManager.loadBySeqAndIntTxnCd(solutionId, intTxnCd);
        }
        return s;
    }

    /**
     * 根据field精确清理缓存
     * @param s
     * @param intTxnCd
     * @param solutionType
     * @param prodCode
     * @param acctId
     */
    private void cleanFeeCacheByField(Solution s ,String intTxnCd, String solutionType, String prodCode, String acctId,String payChannel){
        String key="",field="";
        try {
            key = FastJsonUtil.getKey(redisConstants.getRedisEnvironment(),Constants.CACHE_CHANNEL_SOLUTION, prodCode,intTxnCd ,solutionType);
            logger.info("1、cleanFeeCacheByField 的key值为："+ key);
            //账户类型不为空的时候清理缓存
            if (StringUtils.isNotEmpty(prodCode)){
                field = acctId+":"+payChannel;
                logger.info("2、cleanFeeCacheByField 的field值为："+ field);
                cacheCleanService.cleanCache(new CacheClean(key, field));
/*                Long hdel = RedisClient.hdel(key, field);
                if (hdel!=null && hdel==1){
                    logger.info("======>第一次清理缓存成功，key为 {}，field为 {}",key,field);
                }else{
                    logger.info("======>第一次数据不存在或清理失败，key为 {}，field为 {}",key,field);
                }*/
            }else{
                logger.info("======>账户类型为空，不清理缓存，key为 {}",key);
            }
            ssTransFeeSoluManager.modifyBySeqAndIntTxnCd(s, intTxnCd);
        } catch (Exception e) {
            logger.error("=====>个性化手续费缓存清理异常：",e);
/*        } finally {
            if (StringUtils.isNotEmpty(prodCode)){
                Long hdel = RedisClient.hdel(key, field);
                if (hdel!=null && hdel==1){
                    logger.info("======>第二次清理缓存成功，key为 {}，field为 {}",key,field);
                }else{
                    logger.info("======>第二次数据不存在或清理失败，key为 {}，field为 {}",key,field);
                }
            }*/
        }
    }

    /**
     * 根据field批量清理缓存
     * @param s
     * @param intTxnCd
     * @param solutionType
     * @param prodCode
     * @param acctId
     */
    private void cleanFeeCacheByAcctId(Solution s ,String intTxnCd, String solutionType, String prodCode, String acctId){
        String key="";
        try {
            key = FastJsonUtil.getKey(redisConstants.getRedisEnvironment(),Constants.CACHE_CHANNEL_SOLUTION, prodCode,intTxnCd ,solutionType);
            logger.info("1、cleanFeeCacheByAcctId 的key值为："+ key);
            //账户类型不为空的时候清理缓存
            if (StringUtils.isNotEmpty(prodCode)){
                //先获取该账户下所有的手续费方案明细
                Solution solution = ssTransFeeSoluManager.loadBySeqAndIntTxnCd(s.getMeta().getSolutionId(), intTxnCd);
                logger.info("2、solution："+ ToStringBuilder.reflectionToString(solution));
                List<SolutionRuleDtl> ruleDtls = solution.getRuleDtls();
                if (ruleDtls!=null){
                    for (SolutionRuleDtl ruleDtl : ruleDtls) {
                        SsTransFeeDtl feeDtl = (SsTransFeeDtl) ruleDtl;
                        if (!"00".equals(feeDtl.getDtlStatus())){
                            continue;
                        }
                        String field = acctId + ":" + feeDtl.getPayChannel();
                        logger.info("2、cleanFeeCacheByAcctId 的field值为："+ field);
                        cacheCleanService.cleanCache(new CacheClean(key, field));
                        //cacheHelper.cleanCache(new CacheClean(CacheCleanType.HDEL, key, field));
/*                        Long hdel = RedisClient.hdel(key, field);
                        if (hdel!=null && hdel==1){
                            logger.info("======>第一次清理缓存成功，key为 {}，field为 {}",key,field);
                        }else{
                            logger.info("======>第一次数据不存在或清理失败，key为 {}，field为 {}",key,field);
                        }*/
                    }
                }else{
                    logger.info("通用手续费未初始化付款渠道，缓存不操作");
                }
            }else{
                logger.info("======>账户类型为空，不清理缓存，key为 {}",key);
            }
            ssTransFeeSoluManager.modifyBySeqAndIntTxnCd(s, intTxnCd);
        } catch (Exception e) {
            logger.error("=====>个性化手续费缓存清理异常：" , e);
/*        } finally {
            if (StringUtils.isNotEmpty(prodCode)){
                //先获取该账户下所有的手续费方案明细
                Solution solution = ssTransFeeSoluManager.loadBySeqAndIntTxnCd(s.getMeta().getSolutionId(), intTxnCd);
                List<SolutionRuleDtl> ruleDtls = solution.getRuleDtls();
                if (ruleDtls!=null){
                    for (SolutionRuleDtl ruleDtl : ruleDtls) {
                        SsTransFeeDtl feeDtl = (SsTransFeeDtl) ruleDtl;
                        if (!"00".equals(feeDtl.getDtlStatus())){
                            continue;
                        }
                        String field = acctId + ":" + feeDtl.getPayChannel();
                        Long hdel = RedisClient.hdel(key, field);
                        if (hdel!=null && hdel==1){
                            logger.info("======>第二次清理缓存成功，key为 {}，field为 {}",key,field);
                        }else{
                            logger.info("======>第二次数据不存在或清理失败，key为 {}，field为 {}",key,field);
                        }
                    }
                }else{
                    logger.info("======>第二次没有手续费方案明细，无需清理，key为{}",key);
                }

            }*/
        }
    }
}